/*     */ package com.zimbra.cs.imap;
/*     */ 
/*     */ import com.google.common.io.Closeables;
/*     */ import com.zimbra.common.io.TcpServerInputStream;
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.stats.StopWatch;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.NetUtil;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.security.sasl.Authenticator;
/*     */ import com.zimbra.cs.server.ProtocolHandler;
/*     */ import com.zimbra.cs.stats.ActivityTracker;
/*     */ import com.zimbra.cs.stats.ZimbraPerf;
/*     */ import java.io.BufferedOutputStream;
/*     */ import java.io.IOException;
/*     */ import java.io.OutputStream;
/*     */ import java.net.InetAddress;
/*     */ import java.net.InetSocketAddress;
/*     */ import java.net.Socket;
/*     */ import java.net.SocketException;
/*     */ import javax.net.ssl.SSLSession;
/*     */ import javax.net.ssl.SSLSocket;
/*     */ import javax.net.ssl.SSLSocketFactory;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ final class TcpImapHandler
/*     */   extends ProtocolHandler
/*     */ {
/*     */   private TcpServerInputStream input;
/*     */   private String remoteIp;
/*     */   private TcpImapRequest request;
/*     */   private final ImapConfig config;
/*     */   private Socket socket;
/*     */   private final HandlerDelegate delegate;
/*     */   
/*     */   TcpImapHandler(TcpImapServer server)
/*     */   {
/*  47 */     super(server);
/*  48 */     this.config = server.getConfig();
/*  49 */     this.delegate = new HandlerDelegate(this.config);
/*     */   }
/*     */   
/*     */   protected boolean setupConnection(Socket connection) throws IOException
/*     */   {
/*  54 */     this.socket = connection;
/*  55 */     this.remoteIp = this.socket.getInetAddress().getHostAddress();
/*  56 */     INFO("connected");
/*     */     
/*  58 */     this.input = new TcpServerInputStream(connection.getInputStream());
/*  59 */     this.delegate.output = new BufferedOutputStream(connection.getOutputStream());
/*     */     
/*  61 */     if (!this.config.isServiceEnabled()) {
/*  62 */       ZimbraLog.imap.debug("dropping connection because user services are disabled");
/*  63 */       dropConnection();
/*  64 */       return false;
/*     */     }
/*     */     
/*  67 */     this.delegate.sendGreeting();
/*     */     
/*  69 */     return true;
/*     */   }
/*     */   
/*     */ 
/*     */   protected boolean authenticate()
/*     */   {
/*  75 */     return true;
/*     */   }
/*     */   
/*     */   protected void setIdle(boolean idle)
/*     */   {
/*  80 */     super.setIdle(idle);
/*  81 */     ImapSession i4selected = this.delegate.selectedFolder;
/*  82 */     if (i4selected != null) {
/*  83 */       i4selected.updateAccessTime();
/*     */     }
/*     */   }
/*     */   
/*     */   protected boolean processCommand() throws IOException
/*     */   {
/*  89 */     this.delegate.setLoggingContext();
/*     */     
/*  91 */     if (this.input == null) {
/*  92 */       clearRequest();
/*  93 */       return false;
/*     */     }
/*  95 */     if (this.request == null) {
/*  96 */       this.request = new TcpImapRequest(this.input, this.delegate);
/*     */     }
/*  98 */     boolean complete = true;
/*     */     try {
/* 100 */       this.request.continuation();
/* 101 */       if (this.request.isMaxRequestSizeExceeded()) {
/* 102 */         setIdle(false);
/* 103 */         throw new ImapParseException(this.request.getTag(), "maximum request size exceeded");
/*     */       }
/*     */       
/* 106 */       long start = ZimbraPerf.STOPWATCH_IMAP.start();
/*     */       
/* 108 */       if (!this.delegate.checkAccountStatus())
/* 109 */         return false;
/*     */       boolean keepGoing;
/*     */       boolean keepGoing;
/* 112 */       if ((this.delegate.authenticator != null) && (!this.delegate.authenticator.isComplete())) {
/* 113 */         keepGoing = this.delegate.continueAuthentication(this.request);
/*     */       } else {
/* 115 */         keepGoing = this.delegate.executeRequest(this.request);
/*     */       }
/*     */       
/* 118 */       setIdle(false);
/* 119 */       long elapsed = ZimbraPerf.STOPWATCH_IMAP.stop(start);
/* 120 */       if (this.delegate.lastCommand != null) {
/* 121 */         ZimbraLog.imap.info("%s elapsed=%d", new Object[] { this.delegate.lastCommand.toUpperCase(), Long.valueOf(elapsed) });
/* 122 */         ZimbraPerf.IMAP_TRACKER.addStat(this.delegate.lastCommand.toUpperCase(), start);
/*     */       } else {
/* 124 */         ZimbraLog.imap.info("(unknown) elapsed=%d", new Object[] { Long.valueOf(elapsed) });
/*     */       }
/* 126 */       return (keepGoing) && ((LC.imap_max_consecutive_error.intValue() <= 0) || (this.delegate.consecutiveError < LC.imap_max_consecutive_error.intValue()));
/*     */     } catch (TcpImapRequest.ImapContinuationException e) {
/* 128 */       this.request.rewind();
/* 129 */       complete = false;
/* 130 */       if (e.sendContinuation) {
/* 131 */         this.delegate.sendContinuation("send literal data");
/*     */       }
/* 133 */       return true;
/*     */     } catch (TcpImapRequest.ImapTerminatedException e) {
/* 135 */       return false;
/*     */     } catch (ImapParseException e) {
/* 137 */       this.delegate.handleParseException(e);
/* 138 */       return (LC.imap_max_consecutive_error.intValue() <= 0) || (this.delegate.consecutiveError < LC.imap_max_consecutive_error.intValue());
/*     */     } catch (ImapException e) {
/* 140 */       ZimbraLog.imap.debug("stop processing", e);
/* 141 */       return false;
/*     */     } catch (IOException e) { boolean bool1;
/* 143 */       if (this.socket.isClosed()) {
/* 144 */         ZimbraLog.imap.debug("stop processing", e);
/* 145 */         return false;
/*     */       }
/* 147 */       throw e;
/*     */     } finally {
/* 149 */       if (complete) {
/* 150 */         clearRequest();
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   private void clearRequest()
/*     */   {
/* 160 */     if (this.request != null) {
/* 161 */       this.request.cleanup();
/* 162 */       this.request = null;
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   protected void notifyIdleConnection()
/*     */   {
/* 172 */     ZimbraLog.imap.debug("dropping connection for inactivity");
/* 173 */     dropConnection();
/*     */   }
/*     */   
/*     */   void INFO(String message, Throwable e) {
/* 177 */     if (ZimbraLog.imap.isInfoEnabled())
/* 178 */       ZimbraLog.imap.info(withClientInfo(message), e);
/*     */   }
/*     */   
/*     */   void INFO(String message) {
/* 182 */     if (ZimbraLog.imap.isInfoEnabled())
/* 183 */       ZimbraLog.imap.info(withClientInfo(message));
/*     */   }
/*     */   
/*     */   private StringBuilder withClientInfo(String message) {
/* 187 */     int length = 64;
/* 188 */     if (message != null) {
/* 189 */       length += message.length();
/*     */     }
/* 191 */     return new StringBuilder(length).append("[").append(this.remoteIp).append("] ").append(message);
/*     */   }
/*     */   
/*     */   protected void dropConnection()
/*     */   {
/* 196 */     this.delegate.dropConnection(true);
/*     */   }
/*     */   
/*     */   ImapHandler setCredentials(ImapCredentials creds) {
/* 200 */     this.delegate.setCredentials(creds);
/* 201 */     return this.delegate;
/*     */   }
/*     */   
/*     */   private final class HandlerDelegate extends ImapHandler
/*     */   {
/*     */     HandlerDelegate(ImapConfig config) {
/* 207 */       super();
/*     */     }
/*     */     
/*     */     String getRemoteIp()
/*     */     {
/* 212 */       return TcpImapHandler.this.remoteIp;
/*     */     }
/*     */     
/*     */     void sendLine(String line, boolean flush) throws IOException
/*     */     {
/* 217 */       ZimbraLog.imap.trace("S: %s", new Object[] { line });
/* 218 */       OutputStream os = this.output;
/* 219 */       if (os == null) {
/* 220 */         return;
/*     */       }
/* 222 */       os.write(line.getBytes());
/* 223 */       os.write(LINE_SEPARATOR_BYTES);
/* 224 */       if (flush) {
/* 225 */         os.flush();
/*     */       }
/*     */     }
/*     */     
/*     */     protected void dropConnection(boolean sendBanner)
/*     */     {
/*     */       try {
/* 232 */         unsetSelectedFolder(false);
/*     */       }
/*     */       catch (Exception e) {}
/*     */       
/*     */ 
/*     */ 
/* 238 */       new Thread()
/*     */       {
/*     */         public void run() {
/* 241 */           if (TcpImapHandler.HandlerDelegate.this.output == null) {
/* 242 */             return;
/*     */           }
/*     */           try {
/* 245 */             sleep(10000L);
/*     */           }
/*     */           catch (InterruptedException e) {}
/* 248 */           Closeables.closeQuietly(TcpImapHandler.HandlerDelegate.this.output);
/*     */         }
/*     */       }.start();
/*     */       
/* 252 */       if ((this.credentials != null) && (!this.goodbyeSent)) {
/* 253 */         ZimbraLog.imap.info("dropping connection for user %s (server-initiated)", new Object[] { this.credentials.getUsername() });
/*     */       }
/*     */       
/* 256 */       ZimbraLog.addIpToContext(TcpImapHandler.this.remoteIp);
/*     */       try {
/* 258 */         OutputStream os = this.output;
/* 259 */         if (os != null) {
/* 260 */           if ((sendBanner) && (!this.goodbyeSent)) {
/* 261 */             sendBYE();
/*     */           }
/* 263 */           os.close();
/* 264 */           this.output = null;
/*     */         }
/* 266 */         if (TcpImapHandler.this.input != null) {
/* 267 */           TcpImapHandler.this.input.close();
/* 268 */           TcpImapHandler.this.input = null;
/*     */         }
/* 270 */         if (this.authenticator != null) {
/* 271 */           this.authenticator.dispose();
/* 272 */           this.authenticator = null;
/*     */         }
/*     */       } catch (IOException e) {
/* 275 */         if (ZimbraLog.imap.isDebugEnabled()) {
/* 276 */           ZimbraLog.imap.debug("I/O error while closing connection", e);
/*     */         } else {
/* 278 */           ZimbraLog.imap.debug("I/O error while closing connection: " + e);
/*     */         }
/*     */       } finally {
/* 281 */         ZimbraLog.clearContext();
/*     */       }
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */     void close()
/*     */     {
/*     */       try
/*     */       {
/* 301 */         TcpImapHandler.this.socket.close();
/*     */       } catch (Throwable e) {
/* 303 */         ZimbraLog.imap.debug("Failed to close socket", e);
/*     */       }
/*     */     }
/*     */     
/*     */     void enableInactivityTimer() throws SocketException
/*     */     {
/* 309 */       TcpImapHandler.this.connection.setSoTimeout(this.config.getAuthenticatedMaxIdleTime() * 1000);
/*     */     }
/*     */     
/*     */     void completeAuthentication() throws IOException
/*     */     {
/* 314 */       TcpImapHandler.this.delegate.setLoggingContext();
/* 315 */       this.authenticator.sendSuccess();
/* 316 */       if (this.authenticator.isEncryptionEnabled())
/*     */       {
/* 318 */         TcpImapHandler.this.input = new TcpServerInputStream(this.authenticator.unwrap(TcpImapHandler.this.connection.getInputStream()));
/* 319 */         this.output = this.authenticator.wrap(TcpImapHandler.this.connection.getOutputStream());
/*     */       }
/*     */     }
/*     */     
/*     */     boolean doSTARTTLS(String tag) throws IOException
/*     */     {
/* 325 */       if (!checkState(tag, ImapHandler.State.NOT_AUTHENTICATED))
/* 326 */         return true;
/* 327 */       if (this.startedTLS) {
/* 328 */         sendNO(tag, "TLS already started");
/* 329 */         return true;
/*     */       }
/* 331 */       sendOK(tag, "Begin TLS negotiation now");
/*     */       
/* 333 */       SSLSocketFactory fac = (SSLSocketFactory)SSLSocketFactory.getDefault();
/* 334 */       SSLSocket tlsconn = (SSLSocket)fac.createSocket(TcpImapHandler.this.connection, TcpImapHandler.this.connection.getInetAddress().getHostName(), TcpImapHandler.this.connection.getPort(), true);
/*     */       
/* 336 */       NetUtil.setSSLProtocols(tlsconn, this.config.getMailboxdSslProtocols());
/* 337 */       NetUtil.setSSLEnabledCipherSuites(tlsconn, this.config.getSslExcludedCiphers(), this.config.getSslIncludedCiphers());
/* 338 */       tlsconn.setUseClientMode(false);
/* 339 */       TcpImapHandler.this.startHandshake(tlsconn);
/* 340 */       ZimbraLog.imap.debug("suite: " + tlsconn.getSession().getCipherSuite());
/* 341 */       TcpImapHandler.this.input = new TcpServerInputStream(tlsconn.getInputStream());
/* 342 */       this.output = new BufferedOutputStream(tlsconn.getOutputStream());
/* 343 */       this.startedTLS = true;
/* 344 */       return true;
/*     */     }
/*     */     
/*     */     InetSocketAddress getLocalAddress()
/*     */     {
/* 349 */       return (InetSocketAddress)TcpImapHandler.this.socket.getLocalSocketAddress();
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/imap/TcpImapHandler.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */